﻿using System;
using YourWorld.Common;
using MainGameModule.Models;
using System.Collections.ObjectModel;
using BusinessObjects;
using YourWorld.Common.Infrastucture.Events;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Practices.Unity;
using System.Linq;
using System.Diagnostics;
using System.Windows.Input;
using Microsoft.Practices.Composite.Presentation.Commands;
using Microsoft.Practices.Composite.Regions;
using MainGameModule.Views;

namespace MainGameModule.ViewModels
{
    public class GameMainViewModel : ViewModelBase
    {
        private Random random = new Random();
        private IUnityContainer container;
        private IRegionManager regionManager;
        private IDataModel dataModel;
        private IGameModel gameModel;
        private Game game;
        private bool isBusy = false;

        private ObservableCollection<GameObject> gameObjectsCollection;

        private Player player;  //The main Player
        private ObservableCollection<Player> players; //All the other players

        private GameControlsViewModel gameControlsViewModel;
        private List<List<int>> grid;
        private ObservableCollection<Event> pendingQuests;

        public ICommand ShowTutorialCommand
        {
            get;
            private set;
        }

        public ICommand ShowWallOfFameCommand
        {
            get;
            private set;
        }

        public GameMainViewModel( IDataModel dataModel, IGameModel gameModel, IUnityContainer container, IRegionManager regionManager )
        {
            this.dataModel = dataModel;
            this.gameModel = gameModel;
            this.container = container;
            this.regionManager = regionManager;

            this.gameModel.InitializeSucceeded += new Action( gameModel_InitializeSucceeded );
            this.gameModel.PlayerActionReceived += new Action<MoveMessage>( gameModel_PlayerActionReceived );
            this.gameModel.BinsUpdateMessageReceived += new Action<BinsUpdateMessage>( gameModel_BinsUpdateMessageReceived );

            this.gameModel.SubscribeSucceeded += new Action<Player>( gameModel_SubscribeSucceeded );
            this.gameModel.GameInitialized += new Action<Game>( gameModel_GameInitialized );

            this.gameModel.SubscribeFailed += new Action<Exception>( gameModel_SubscribeFailed );
            this.gameModel.UnSubscribeSucceeded += new Action( gameModel_UnSubscribeSucceeded );
            this.gameModel.PlayerUnsubscribed += new Action<int>( gameModel_PlayerUnsubscribed );

            this.gameModel.RubbishUpdateReceived += new Action<List<RegionObjectHolder>>( gameModel_RubbishUpdateReceived );
            this.gameModel.PublishBuildQuestReceived += new Action<int, int, RegionObjectHolder>( PublishBuildQuestReceived );
            this.gameModel.PublishBadgeWon += new Action<BadgeUpdateHolder>( gameModel_PublishBadgeWon );

            this.gameModel.QuestResponseReceived += this.QuestResponseReceived;
            this.gameModel.BuildQuestRequestReceived += new Action<Event>( gameModel_BuildQuestRequestReceived );
            this.gameModel.BuildTeamQuestRequestReceived += new Action<TeamEvent>( gameModel_BuildTeamQuestRequestReceived );

            this.gameModel.QuestCompleted += new Action<TeamEvent>( gameModel_QuestCompleted );

            this.UnsubscribeCommand = new DelegateCommand<object>( this.UnsubscribePlayer );
            EventService.Aggregator.GetEvent<ScaleGameMapEvent>().Subscribe( this.GameScaleChanged );
            EventService.Aggregator.GetEvent<BuildQuestEvent>().Subscribe( this.BuildQuest );

            this.IsBusy = true;

            QuestsPreviewViewModel questsPreviewPanel = this.container.Resolve<QuestsPreviewViewModel>();
            questsPreviewPanel.EventCompleted = this.EventCompleted;

            PlayerStatusManager.Instance.ExperienceChanged += new Action<int>( x => { this.Player.Experience += x; } );
        }
        
        public bool IsBusy
        {
            get
            {
                return this.isBusy;
            }
            set
            {
                if ( this.isBusy == value )
                    return;

                this.isBusy = value;
                this.NotifyPropertyChanged( "IsBusy" );
            }
        }

        public List<List<int>> Grid
        {
            get
            {
                if ( this.grid == null )
                    this.grid = new List<List<int>>();

                return this.grid;
            }
        }

        public GameControlsViewModel GameControlsViewModel
        {
            get
            {
                if ( this.gameControlsViewModel == null )
                    this.gameControlsViewModel = this.container.Resolve<GameControlsViewModel>();

                return this.gameControlsViewModel;
            }
        }

        public ObservableCollection<GameObject> GameObjectsCollection
        {
            get
            {
                if ( this.gameObjectsCollection == null )
                    this.gameObjectsCollection = new ObservableCollection<GameObject>();

                return this.gameObjectsCollection;
            }
            set
            {
                if ( this.gameObjectsCollection == value )
                    return;

                this.gameObjectsCollection = value;
                this.NotifyPropertyChanged( "GameObjectsCollection" );
            }
        }

        public Player Player
        {
            get
            {
                return this.player;
            }
            set
            {
                if ( this.player == value )
                    return;

                this.player = value;
                this.NotifyPropertyChanged( "Player" );
            }
        }

        public ObservableCollection<Player> Players
        {
            get
            {
                if ( this.players == null )
                    this.players = new ObservableCollection<Player>();

                return this.players;
            }
            set
            {
                if ( this.players == value )
                    return;

                this.players = value;
                this.NotifyPropertyChanged( "Players" );
            }
        }

        public ObservableCollection<Event> PendingQuests
        {
            get
            {
                if ( this.pendingQuests == null )
                    this.pendingQuests = new ObservableCollection<Event>();

                return this.pendingQuests;
            }
        }

        public Game Game
        {
            get
            {
                return this.game;
            }
            set
            {
                if ( this.game == value )
                    return;

                this.game = value;
            }
        }

        public double GameScale
        {
            get;
            set;
        }

        public ICommand UnsubscribeCommand
        {
            get;
            private set;
        }

        public void InitializeGameModel()
        {
            this.gameModel.InitializeCommunicator();
        }

        public void GameScaleChanged( double scale )
        {
            this.GameScale = scale;
        }

        public void RubbishFound( Rubbish rubbish )
        {
            Debug.Assert( this.Game.Grid[rubbish.GridX][rubbish.GridY] == rubbish.Id );
            this.Game.Grid[rubbish.GridX][rubbish.GridY] = 0;

            this.GameObjectsCollection.Remove( rubbish );
            RubbishBinsRepository.Instance.AddRubbsihToBin( rubbish, rubbish.MaterialTypeId );
            this.gameModel.UpdateSeverBinsStatus( this.Player, rubbish );
        }

        public BadgesViewModel GetBadgesViewModel()
        {
            return this.container.Resolve<BadgesViewModel>();
        }

        /// <summary>
        /// Called when starting the quest from the GameEventsViewModel window
        /// </summary>
        /// <param name="quest"></param>
        public void BuildQuestRequest( Event quest )
        {
            foreach ( UserBadge ub in quest.RequiredBadges )
                ub.IsLocked = true;

            quest.IsSingleInitiated = quest.RequiredMembersCount == 1;
            quest.IsBuild = quest.Type == RegionObjectTypes.Build;
            quest.PlayerId = this.Player.Id;
            quest.MapId = this.Player.MapId;

            bool canBuild = true;
            UserBadge badge;
            quest.RequiredBadges.Clear();

            foreach ( int badgeId in quest.RequiredBadgesIds )
            {
                badge = BadgesRepository.Instance.GetBadge( badgeId );
                quest.RequiredBadges.Add( badge );

                    //this.Player.BadgesCollection.Where( x => x.Id == badgeId ).FirstOrDefault();
            }
           

            QuestsPreviewViewModel questsPreviewPanel = this.container.Resolve<QuestsPreviewViewModel>();
            questsPreviewPanel.PendingQuests.Add( quest );
            //string showText;

            //if ( canBuild == true )
            //{
            //    this.gameModel.StartEvent( quest );
            //    this.PendingQuests.Add( quest );

            //    QuestsPreviewViewModel questsPreviewPanel = this.container.Resolve<QuestsPreviewViewModel>();
            //    questsPreviewPanel.PendingQuests.Add( quest );

            //    if ( quest.IsSingleInitiated == false )
            //    {
            //        showText = "Great Job! You have all the required badges! You have selected a team quest which" +
            //            " means that it will be completed only after the scecified number of players is reached (2 players)." +
            //            " Good luck and stick around surely your friends will soon join you in this quest!";

            //        EventService.Aggregator.GetEvent<ShowInfoBoxEvent>().Publish( showText );
            //    }

            //    //EventService.Aggregator.GetEvent<BuildQuestEvent>().Publish( qst );
            //}
            //else
            //{
            //    showText = "Great Work! But You still don't have all the required badges! Go and recycle more rubbishes and connect with friends and you will soon be able to finish your job here. Good luck!";
            //    EventService.Aggregator.GetEvent<ShowInfoBoxEvent>().Publish( showText );
            //}
        }

        private void EventCompleted( Event quest )
        {
            this.gameModel.StartEvent( quest );
            this.PendingQuests.Add( quest );
        }

        private void QuestResponseReceived( EventFeedback feedback, bool isJoin )
        {
            PlayerStatusManager.Instance.PauseGame();

            JoinSupportQuestViewModel vm = this.container.Resolve<JoinSupportQuestViewModel>();
            vm.Initialize();

            vm.Quest = feedback.GameEvent;
            vm.Sender = PlayersRepository.Instance.GetPlayer( feedback.SenderId );
            vm.HeaderText = "QUESTS";
            vm.OtherPlayerId = this.player.Id;
            vm.OtherPlayerName = this.player.Name;
            vm.IsQuestResponse = true;
            vm.Comments = feedback.Feedback;

            UserBadge badge;
            Event questEvent = this.PendingQuests.Where( x => x.Id == feedback.GameEvent.Id ).FirstOrDefault();
            if ( questEvent != null )
            {
                foreach ( UserBadge b in vm.Sender.BadgesCollection )
                {
                    badge = questEvent.RequiredBadges.Where( x => x.Id == b.Id ).FirstOrDefault();

                    if ( badge != null )
                        badge.IsLocked = false;
                }

                if ( questEvent.Type == RegionObjectTypes.Build )
                    vm.CanBuildObject = true;

                foreach ( UserBadge ub in questEvent.RequiredBadges )
                {
                    if ( ub.IsLocked == true )
                    {
                        if ( questEvent.Type == RegionObjectTypes.Build )
                            vm.CanBuildObject = false;

                        break;
                    }
                }
            }

            if ( isJoin == true )
                vm.Greeting = vm.Sender.Name + " has joined your Quest!";
            else
                vm.Greeting = vm.Sender.Name + " likes your quest very much and is also eager to take some quests!";

            if ( this.regionManager.Regions[RegionNames.GamePopUpRegion].Views.Contains( this.container.Resolve<EventsJoinOrSupportView>() ) == false )
                this.regionManager.RegisterViewWithRegion( RegionNames.GamePopUpRegion, typeof( EventsJoinOrSupportView ) );

            this.regionManager.Regions[RegionNames.GamePopUpRegion].Activate( this.container.Resolve<EventsJoinOrSupportView>() );
        }

        private Quest InitializeQuest( int questId )
        {
            Quest quest = new Quest();
            quest.Id = questId;

            YourWorld.Common.GreenWorldEntitiesService.RegionObject ro = RegionObjectsRepository.Instance.RegionObjects[quest.Id];
            Debug.Assert( ro != null );

            quest.X = 0;
            quest.Y = 0;
            quest.Width = ro.Width ?? 100;
            quest.Height = ro.Height ?? 100;
            quest.Description = ro.Description;
            quest.Image = ro.Image;

            quest.QuestType = ( BuildQuestTypes )Enum.Parse( typeof( BuildQuestTypes ), ro.Template, true );

            return quest;
        }

        public void BuildQuest( Quest quest )
        {
            if ( quest.QuestType != BuildQuestTypes.Causes )
            {
                if ( quest.X == 0 && quest.Y == 0 )
                    return;

                PlayersRepository.Instance.SavePlayerQuestId( this.Player.Id, quest.Id, null );
                Event gameEvent = this.PendingQuests.Where(x =>x.Id == quest.Id).FirstOrDefault();

                Debug.Assert( gameEvent != null );
                this.Player.QuestsCollection.Add( gameEvent );

                this.AddQuestToMap( quest );
            }

            BuildQuestUpdateHolder update = new BuildQuestUpdateHolder();
            update.RegionObject = new RegionObjectHolder( quest.Id, ( int )quest.X, ( int )quest.Y );
            update.PlayerId = this.Player.Id;
            update.MapId = this.Player.MapId;
            update.QuestId = quest.Id;

            this.gameModel.PublishBuildQuest( update );
        }

        private void gameModel_BuildTeamQuestRequestReceived( TeamEvent task )
        {
            //Show messagebox
           // MessageBox.Show( "BuildTeamQuestRequestReceived" );

            JoinSupportQuestViewModel vm = this.container.Resolve<JoinSupportQuestViewModel>();
            vm.Initialize();

            vm.Quest = task.Quest;
            vm.HeaderText = "QUESTS";
            vm.OtherPlayerId = this.Player.Id;
            vm.OtherPlayerName = this.Player.Name;            
            vm.CanBuildObject = true;

            foreach ( Player p in task.Members )
            {
                Player loadedPlayer = PlayersRepository.Instance.GetPlayer( p.Id );
                if ( loadedPlayer.Image == null )
                    loadedPlayer.Image = this.Player.Image;

                vm.Members.Add( loadedPlayer );
            }

            if ( this.regionManager.Regions[RegionNames.GamePopUpRegion].Views.Contains( this.container.Resolve<EventsJoinOrSupportView>() ) == false )
                this.regionManager.RegisterViewWithRegion( RegionNames.GamePopUpRegion, typeof( EventsJoinOrSupportView ) );

            this.regionManager.Regions[RegionNames.GamePopUpRegion].Activate( this.container.Resolve<EventsJoinOrSupportView>() );

            Quest qst = this.InitializeQuest( task.Quest.Id );
            EventService.Aggregator.GetEvent<BuildQuestEvent>().Publish( qst );
        }

        private void gameModel_BuildQuestRequestReceived( Event quest )
        {
            JoinSupportQuestViewModel vm = this.container.Resolve<JoinSupportQuestViewModel>();
            vm.Initialize();

            vm.Quest = quest;
            vm.Sender = PlayersRepository.Instance.GetPlayer( quest.PlayerId );
            vm.HeaderText = "BUILD";
            vm.OtherPlayerId = this.player.Id;
            vm.OtherPlayerName = this.player.Name;
            vm.CanBuildObject = true;

            if ( this.regionManager.Regions[RegionNames.GamePopUpRegion].Views.Contains( this.container.Resolve<EventsJoinOrSupportView>() ) == false )
                this.regionManager.RegisterViewWithRegion( RegionNames.GamePopUpRegion, typeof( EventsJoinOrSupportView ) );

            this.regionManager.Regions[RegionNames.GamePopUpRegion].Activate( this.container.Resolve<EventsJoinOrSupportView>() );

            //MessageBox.Show( "BuildQuestRequestReceived" );

            string showText = "Great Work! You have achieved everything needed to build the + " + quest.Title + "!" +
                "In order to choose a place where the object will be build, " +
                "click ok and click once with the right mouse button on the desired place.";

            EventService.Aggregator.GetEvent<ShowInfoBoxEvent>().Publish( showText );

            Quest qst = this.InitializeQuest( quest.Id );
            EventService.Aggregator.GetEvent<BuildQuestEvent>().Publish( qst );
        }

        private void PublishBuildQuestReceived( int questId, int senderId, RegionObjectHolder roh )
        {
            Event gameEvent = RegionObjectsRepository.Instance.GetQuest( questId );
            Debug.Assert( gameEvent != null, "There is no quest with id = " + questId + " in the local repository!" );

            if ( this.Player.Id == senderId )
            {
                string showText = "Great Work! You have all the required badges! ";

                if ( gameEvent.Type == RegionObjectTypes.Causes )
                    showText += "You are now a proud member of this cause! All your friends on the map" +
                                " will hear about your acomplishments! Once again, Great Job!";

                PlayersRepository.Instance.SavePlayerQuestId( this.Player.Id, questId, null );
                this.Player.QuestsCollection.Add( gameEvent );
                EventService.Aggregator.GetEvent<ShowInfoBoxEvent>().Publish( showText );
            }
            else
            {
                Player sender = PlayersRepository.Instance.GetPlayer( senderId );
                Debug.Assert( sender != null );

                if ( sender != null )
                    sender.QuestsCollection.Add( gameEvent );
            }

            if ( gameEvent.Type != RegionObjectTypes.Build || roh == null )
                return;

            // Build the quest's region object and show it on the map of all players
            Quest quest = new Quest();
            quest.Id = roh.RegionObjectId;

            YourWorld.Common.GreenWorldEntitiesService.RegionObject ro = RegionObjectsRepository.Instance.RegionObjects[quest.Id];
            Debug.Assert( ro != null, "There should be a regionobject with id = " + quest.Id );
            quest.QuestType = ( BuildQuestTypes )Enum.Parse( typeof( BuildQuestTypes ), ro.Template, true );

            if ( quest.QuestType == BuildQuestTypes.Causes )
                return;

            quest.X = roh.X;
            quest.Y = roh.Y;
            quest.Width = ro.Width ?? 100;
            quest.Height = ro.Height ?? 100;
            quest.Description = ro.Description;
            quest.Image = ro.Image;
            quest.QuestType = ( BuildQuestTypes )Enum.Parse( typeof( BuildQuestTypes ), ro.Template, true );

            this.AddQuestToMap( quest );
        }

        private void gameModel_PublishBadgeWon( BadgeUpdateHolder buh )
        {
            Debug.Assert( this.Player.Id != buh.PlayerId, "The main player shouln't be getting a badge status update!" );
            Player player = PlayersRepository.Instance.GetPlayer( buh.PlayerId );

            player.Badges = String.Format( "{0},{1}", buh.BadgeId, player.Badges );

            UserBadge ub = BadgesRepository.Instance.GetBadge( buh.BadgeId );
            Debug.Assert( ub != null );
            player.BadgesCollection.Add( ub );
        }

        private void AddQuestToMap( Quest quest )
        {
            int gridx = this.Game.Grid.Count - ( int )( quest.Y / Consts.MapTileWidth ) - 1;
            int gridy = ( int )( quest.X / Consts.MapTileHeight ) - 1;

            if ( gridx < 0 || gridy < 0 || this.Game.Grid[gridx][gridy] == Consts.Unreachable )
                return;

            int xw = gridx - ( int )( quest.Height / Consts.MapTileWidth ) + 1;
            int yw = gridy + ( int )( quest.Width / Consts.MapTileHeight );

            for ( int i = xw; i < gridx; i++ )
            {
                for ( int j = gridy; j < yw; j++ )
                {
                    if ( quest.QuestType == BuildQuestTypes.WaterPlant )
                        this.Game.Grid[i][j] = Consts.Unreachable;
                    else
                        this.Game.Grid[i][j] = -1;
                }
            }

            this.GameObjectsCollection.Insert( 0, quest );
            EventService.Aggregator.GetEvent<UpdateLayoutEvent>().Publish( true );
        }

        private void UnsubscribePlayer( object o )
        {
            if ( this.Player != null )
                this.gameModel.UnSubscribe( this.Player );
        }

        private void gameModel_QuestCompleted( TeamEvent quest )
        {
            //MessageBox.Show( this.Player.Name + " - " + quest.Quest.Title );
            PlayerStatusManager.Instance.PauseGame();

            JoinSupportQuestViewModel vm = this.container.Resolve<JoinSupportQuestViewModel>();
            vm.Initialize();            
            vm.Quest = quest.Quest;
            vm.HeaderText = "QUESTS";
            vm.OtherPlayerId = this.Player.Id;
            vm.OtherPlayerName = this.Player.Name;
            vm.IsQuestResponse = true;

            foreach ( Player p in quest.Members )
            {
                Player loadedPlayer = PlayersRepository.Instance.GetPlayer( p.Id );
                if ( loadedPlayer.Image == null )
                    loadedPlayer.Image = this.Player.Image;

                vm.Members.Add( loadedPlayer );
            }
            
            if ( this.regionManager.Regions[RegionNames.GamePopUpRegion].Views.Contains( this.container.Resolve<EventsJoinOrSupportView>() ) == false )
                this.regionManager.RegisterViewWithRegion( RegionNames.GamePopUpRegion, typeof( EventsJoinOrSupportView ) );

            this.regionManager.Regions[RegionNames.GamePopUpRegion].Activate( this.container.Resolve<EventsJoinOrSupportView>() );
            // add quest to map - 
            this.PublishBuildQuestReceived( quest.Id, quest.Quest.PlayerId, quest.RegionObject );
        }

        private void gameModel_UnSubscribeSucceeded()
        {
            //System.Windows.MessageBox.Show( "Unsubscribe Ok :)" );
        }

        /// <summary>
        /// Called when another player gets on the same map.
        /// </summary>
        /// <param name="player"></param>
        private void gameModel_SubscribeSucceeded( Player player )
        {
            // Player p = PlayersRepository.Instance.GetPlayer( player.Id );
            // p.Id = player.Id;

            if ( player.IsGuest == true )
            {
                //The player is not available in the local Players collection.
                PlayersRepository.Instance.LoadPlayerProperties( player );
                PlayersRepository.Instance.Players.Add( player );
            }
            else
            {
                Player p = PlayersRepository.Instance.GetPlayerByUserId( player.UserId );
                Debug.Assert( p != null, "No user with id = " + player.UserId + " in the local DB!" );

                p.Id = player.Id;
                p.Image = player.Image;
            }

            player.X = Consts.InitialPlayerX;
            player.Y = Consts.InitialPlayerY;

            this.GameObjectsCollection.Add( player );
            this.Players.Add( player );
            
            EventService.Aggregator.GetEvent<UpdateLayoutEvent>().Publish( true );
        }

        /// <summary>
        /// Called once for the main player in the game.
        /// Contains all map objects includeing the players in the game.
        /// The main player is marked with the IsMainPlayer = true.
        /// </summary>
        /// <param name="game"></param>
        private void gameModel_GameInitialized( Game game )
        {
            this.IsBusy = false;
            this.Game = game;
            Player p;

            foreach ( GameObject go in game.GameObjects )
                this.GameObjectsCollection.Add( go );

            foreach ( Player player in game.Players )
            {
                Debug.Assert( this.Player != null );

                if ( player.IsMainPlayer == true )
                {
                    // we have already set the player :)
                    this.Player.Id = player.Id;
                    this.Player.MapId = player.MapId;

                    PlayerStatusManager.Instance.StartGame();
                    this.GameObjectsCollection.Add( this.Player );

                    if ( player.IsGuest == true )
                    {
                        PlayersRepository.Instance.Players.Add( player );
                    }
                    else
                    {
                        p = PlayersRepository.Instance.GetPlayerByUserId( player.UserId );
                        p.Id = this.Player.Id;
                        p.MapId = this.Player.MapId;
                    }
                }
                else if ( player.IsGuest == true )
                {
                    PlayersRepository.Instance.LoadPlayerProperties( player );
                    PlayersRepository.Instance.Players.Add( player );

                    this.Players.Add( player );
                    this.GameObjectsCollection.Add( player );
                }
                else if ( player.IsGuest == false )
                {
                    p = PlayersRepository.Instance.GetPlayerByUserId( player.UserId );
                    p.Badges = player.Badges;
                    p.Quests = player.Quests;

                    PlayersRepository.Instance.LoadPlayerProperties( p );
                    player.BadgesCollection = p.BadgesCollection;
                    player.QuestsCollection = p.QuestsCollection;
                    player.PlayerConnections = p.PlayerConnections;
                    player.Connections = p.Connections;

                    Debug.Assert( p != null, "No user with id = " + player.UserId + " in the local DB!" );

                    p.Id = player.Id;
                    p.Image = player.Image;

                    this.Players.Add( player );
                    this.GameObjectsCollection.Add( player );
                }
            }

            EventService.Aggregator.GetEvent<PlayerChangedPositionEvent>().Publish( new Point( this.Player.X, this.Player.Y ) );
        }

        private void gameModel_RubbishUpdateReceived( List<RegionObjectHolder> rubbishObjects )
        {
            foreach ( RegionObjectHolder roh in rubbishObjects )
                this.Game.Grid[roh.X][roh.Y] = roh.RegionObjectId;

            this.gameModel.LoadRegionObjectsFromGrid( this.Game );

            foreach ( GameObject go in this.Game.GameObjects )
            {
                if ( go is Rubbish && this.GameObjectsCollection.Contains( go ) == false )
                    this.GameObjectsCollection.Add( go );
            }

            EventService.Aggregator.GetEvent<UpdateLayoutEvent>().Publish( true );
        }

        private void gameModel_SubscribeFailed( Exception obj )
        {
            MessageBox.Show( obj.Message );
        }

        private void gameModel_PlayerActionReceived( MoveMessage message )
        {
            Player player;
            if ( this.Player.Id == message.PlayerId )
            {
                player = this.Player;
            }
            else
            {
                player = this.Players.Where( obj => obj.Id == message.PlayerId ).FirstOrDefault();
            }

            Debug.Assert( player != null, "Player Inicialization Error!" );

            double x = message.X;
            double y = message.Y;

            //switch ( message.MoveDirection )
            //{
            //    case MoveDirection.Down: y -= Consts.PlayerStep; break;
            //    case MoveDirection.Up: y += Consts.PlayerStep; break;
            //    case MoveDirection.Left: x -= Consts.PlayerStep; break;
            //    case MoveDirection.Right: x += Consts.PlayerStep; break;
            //}

            Debug.Assert( player != null );

            SimplePoint curLoc = new SimplePoint()
            {
                X = player.X,
                Y = player.Y
            };
            SimplePoint newLoc = new SimplePoint()
            {
                X = x,
                Y = y
            };

            player.X = x;
            player.Y = y;

            SimpleTask task = new SimpleTask( newLoc, curLoc, player, () =>
                                {
                                    player.ActualX = x;
                                    player.ActualY = y;

                                    int gridx = this.Game.Grid.Count - ( int )( y / Consts.MapTileWidth ) - 1;
                                    int gridy = ( int )( x / Consts.MapTileHeight );

                                    if ( gridx >= 0 && gridy >= 0 && gridx < this.Game.Grid.Count && gridy < this.Game.Grid[gridx].Count )
                                    {
                                        if ( this.Game.Grid[gridx][gridy] < 0 )
                                            player.ZIndex = this.Game.Grid[gridx][gridy];
                                        else
                                            player.ZIndex = this.Game.Grid[gridx][gridy];
                                    }

                                    if ( player.Id == this.Player.Id )
                                        EventService.Aggregator.GetEvent<PlayerChangedPositionEvent>().Publish( new Point( player.X, player.Y ) );

                                }, Consts.MovePlayerDuration );
            GameTaskManager.Instance.PublishTask( task );

            // Check for the message's Payload and should the Rubbish Pop up if needed :)
            if ( message.Payload != null && message.Payload.Type == ObjectsType.Rubbish )
            {
                int rubbishId = message.Payload.Id;
                GameObject go = this.GameObjectsCollection.Where( ( o ) => o.GridX == message.Payload.GridX && o.GridY == message.Payload.GridY ).FirstOrDefault();

                if ( go == null || go is Rubbish == false )
                    return;

                if ( message.PlayerId == this.Player.Id )
                {
                    EventService.Aggregator.GetEvent<ThrowRubbishEvent>().Publish( go as Rubbish );
                }
                else
                {
                    go.IsEnabled = false;
                }
            }
        }

        private void gameModel_BinsUpdateMessageReceived( BinsUpdateMessage message )
        {
            GameObject go = this.GameObjectsCollection.Where(
                ( o ) => o.GridX == message.RubbishGridX && o.GridY == message.RubbishGridY ).FirstOrDefault();

            Debug.Assert( go != null && go is Rubbish );
            Rubbish rubbish = go as Rubbish;

            switch ( message.MessageStatus )
            {
                case RubbishRemovalStatus.Remove:

                    Debug.Assert( this.Game.Grid[message.RubbishGridX][message.RubbishGridY] == message.RubbishId );
                    this.Game.Grid[message.RubbishGridX][message.RubbishGridY] = 0;

                    this.GameObjectsCollection.Remove( go );
                    RubbishBinsRepository.Instance.AddRubbsihToMapBin( rubbish, rubbish.MaterialTypeId );
                    break;

                case RubbishRemovalStatus.Unlock:
                    go.IsEnabled = true;
                    break;
            }
        }

        private void gameModel_InitializeSucceeded()
        {
            MessageBox.Show( "Initialization OK" );
        }

        private void gameModel_PlayerUnsubscribed( int id )
        {
            if ( this.Player.Id == id )
            {
                this.Player = null;
                this.GameObjectsCollection.Clear();
                // Go to Login Page
                EventService.Aggregator.GetEvent<LogoutEvent>().Publish( null );
                this.gameModel.DisconnectMainPlayer();
            }

            Player p = this.Players.Where( x => x.Id == id ).FirstOrDefault();
            if ( p != null )
                this.Players.Remove( p );

            GameObject go = this.GameObjectsCollection.Where( x => x.Id == id && x is Player == true ).FirstOrDefault();
            if ( go != null )
                this.GameObjectsCollection.Remove( go );
        }

        protected override void OnDispose()
        {
            this.gameModel.UnSubscribe( this.Player );
            base.OnDispose();
        }
    }
}
